package web.service.rest;

import cn.edu.hit.mongodb.DBHelper;
import cn.edu.hit.mongodb.Utils;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.apache.commons.lang3.StringUtils;
import cn.edu.hit.core.Document;
import org.bson.types.ObjectId;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

@Path("/config")
public class ConfigureService {
    private DBHelper dbHelper = new DBHelper();
    final static Map<String, Boolean> isRunMap = Collections.singletonMap("isRun", true);

    @Context
    HttpServletRequest request;

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Map<String, Boolean> isRun() {
        return isRunMap;
    }

    /**
     * TODO 约定 persistXXX 的路径 应与 XXX.type 一致,下同
     */
    @POST
    @Path("/{name}/{type}")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes({MediaType.APPLICATION_FORM_URLENCODED})
    public List<Map> persist(
            @PathParam("name") String name, @PathParam("type") String type, @DefaultValue("json") @QueryParam("format") String format, @FormParam("content") String content) throws IOException {
//        String content = IOUtils.toString(request.getInputStream(),"utf8");
        name = StringUtils.trim(name);
        type = StringUtils.trim(type);
        List<Map> configure;
        TypeFactory typeFactory = TypeFactory.defaultInstance();
        JavaType mapType = typeFactory.constructRawMapType(Map.class);
        JavaType arrayMap = typeFactory.constructCollectionType(List.class, mapType);
        if ("xml".equalsIgnoreCase(format)) {
            XmlMapper xmlMapper = new XmlMapper();
            configure = xmlMapper.readValue(content, arrayMap);
        } else {
            ObjectMapper mapper = new ObjectMapper();
            configure = mapper.readValue(content, arrayMap);
        }
        if (configure == null) {
            return Collections.emptyList();
        }
        try {
            return dbHelper.persistConfigures(name, type, configure);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }


    @POST
    @Path("/component")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes({MediaType.APPLICATION_FORM_URLENCODED})
    public Map persistComponent(@DefaultValue("json") @QueryParam("format") String format, @FormParam("content") String content) throws IOException {
        List<Map> configure;
        TypeFactory typeFactory = TypeFactory.defaultInstance();
        JavaType mapType = typeFactory.constructRawMapType(Map.class);
        JavaType arrayMap = typeFactory.constructCollectionType(List.class, mapType);
        if ("xml".equalsIgnoreCase(format)) {
            XmlMapper xmlMapper = new XmlMapper();
            configure = xmlMapper.readValue(content, arrayMap);
        } else {
            ObjectMapper mapper = new ObjectMapper();
            configure = mapper.readValue(content, arrayMap);
        }
        if (configure == null) {
            return Collections.emptyMap();
        }
        try {
            List<Map> persistResult = dbHelper.persistConfigures("global", "component", configure);


            if (persistResult != null && persistResult.size() > 0)
                return persistResult.get(0);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Collections.emptyMap();
    }


    @DELETE
    @Path("/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Map<String, Boolean> remove(@PathParam("id") String id) {
        id = StringUtils.trim(id);
        boolean isOk = dbHelper.removeConfigure(id);
        return Collections.singletonMap("isOK", isOk);
    }

    @GET
    @Path("/load/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Map<String, Object> loadById(@PathParam("id") String id) {
        id = StringUtils.trim(id);
        Document document = dbHelper.loadConfigureDocument(id);
        if (document == null) {
            return Collections.emptyMap();
        }
        document.put("_id", id);
        return document;
    }

//    @GET
//    @Path("/relation/{id}/{type}")
//    @Produces(MediaType.APPLICATION_JSON)
//    public List<String> loadConfigureRelations(@PathParam("id") String id,@PathParam("type") String type){
//        return dbHelper.loadConfigureRelations(id,type);
//    }

    @POST
    @Path("/query")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes({MediaType.APPLICATION_FORM_URLENCODED})
    /**
     * 根据模版查询
     */
    public List<Map<String, Object>> loadByTemplate(@FormParam("content") String content) throws IOException {
        MongoDatabase database = Utils.getDatabase("fault");
        MongoCollection<Document> configures = database.getCollection("configure", Document.class);
        /**
         * content 为查询模版，json格式
         */
//        String content = IOUtils.toString(request.getInputStream(),"utf8");
        Document document = Utils.parse(content);
        if (document.containsKey("_id")) {
            String _id = document.getString("_id");
            document.put("_id", new ObjectId(_id));
        }
        return StreamSupport.stream(
                configures.find(Utils.toBson(document))
                        .map(d -> {
                            d.put("_id", d.getObjectId("_id"));
//                            return d.toJson(JSON_WRITER_SETTINGS);
                            return d;
                        })
                        .spliterator(), true).collect(Collectors.toList());
    }

    private Map<String, Object> singleValue(Object value) {
        return Collections.singletonMap("value", value);
    }

    public void setRequest(HttpServletRequest request) {
        this.request = request;
    }
}
